package cn.song.utils.easyexcel;


import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.handler.CellWriteHandler;

import cn.song.utils.easyexcel.model.NoModelWriteData;
import cn.song.utils.easyexcel.model.SimpleWriteData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;


/**
 * EasyExcel工具类
 *
 * @author SongRenShuo
 * @date 2023/12/25
 */
@Slf4j
@Component
public class EasyExcelUtils {


    /**
     * 没有模式写入
     * 不创建对象的导出
     *
     * @param data                   数据
     * @param response               响应
     * @param customCellWriteHandler 自定义单元格写入处理程序 - 可为null
     * @throws IOException ioexception
     * @author SongRenShuo
     */
    @Async
    public void noModleWrite(@RequestBody NoModelWriteData data, HttpServletResponse response, CellWriteHandler customCellWriteHandler) throws IOException {
        // 这里注意 使用swagger 会导致各种问题，请直接用浏览器或者用postman
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            if (customCellWriteHandler == null) {
                // 这里需要设置不关闭流
                EasyExcel.write(response.getOutputStream())
                        .head(head(data.getHeadMap()))
                        .sheet(data.getFileName())
                        .doWrite(dataList(data.getDataList(), data.getDataStrMap()));
            } else {
                // 这里需要设置不关闭流
                EasyExcel.write(response.getOutputStream())
                        .head(head(data.getHeadMap()))
                        .sheet(data.getFileName())
                        // 自定义颜色样式
                        .registerWriteHandler(customCellWriteHandler)
                        .doWrite(dataList(data.getDataList(), data.getDataStrMap()));
            }
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = new HashMap<String, String>();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSONUtil.toJsonStr(map));
        }
    }


    /**
     * 创建对象的导出
     *
     * @param data                   数据
     * @param clazz                  clazz
     * @param response               响应
     * @param customCellWriteHandler 自定义单元格写入处理程序 - 可为null
     * @throws IOException ioexception
     * @author SongRenShuo
     */
    @Async
    public <T> void simpleWrite(@RequestBody SimpleWriteData data, Class<T> clazz, HttpServletResponse response, CellWriteHandler customCellWriteHandler) throws IOException {
        // 这里注意 有反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        if (customCellWriteHandler == null) {
            EasyExcel.write(response.getOutputStream(), clazz)
                    .sheet(data.getFileName())
                    .doWrite(data.getDataList());
        } else {
            EasyExcel.write(response.getOutputStream(), clazz)
                    .sheet(data.getFileName())
                    // 自定义颜色样式
                    .registerWriteHandler(customCellWriteHandler)
                    .doWrite(data.getDataList());
        }

    }


    /**
     * 文件下载 - 调用示例
     *
     * @param entity    查询实体
     * @param startTime 开始时间 - 默认当天00:00:00
     * @param endTime   结束时间 - 默认当天23:59:59
     * @author SongRenShuo
     */
//    @RequestMapping("download")
//    public void download(Object entity, String startTime, String endTime, HttpServletResponse response) throws IOException {
//        log.info("文件下载 - 调用示例");
//
//        // 如果为空则默认获取当天时间
//        Date[] isNullDate = getIsNullDate(startTime, endTime);
//        Date parseDate = isNullDate[0];
//        Date endDate = isNullDate[1];
//        // 获取相差天数
//        long between = getBetween(parseDate, endDate, "day");
//        System.out.println("文件下载 - 其他订单 相差天数 = " + between);
//        if (between > 31) {
//            response.setCharacterEncoding("UTF-8");
//            response.setContentType("application/json;charset=utf-8");
//            response.getWriter().println(JSONUtil.toJsonStr(failed("时间区间过长，不允许超过30天")));
//        } else {
//            // 需要导出的数据
//            ArrayList<Object> data = new ArrayList<>();
//
//            // 导出
//            SimpleWriteData d = new SimpleWriteData();
//            d.setFileName("导出示例");
//            d.setDataList(data);
//            EasyExcelUtils easyExcelUtils = new EasyExcelUtils();
//            easyExcelUtils.simpleWrite(d, Object.class, response, null);
//        }
//
//    }


    /**
     * 文件上传 - 调用示例
     *
     * @param file 文件
     * @return 上传成功/失败
     * @author SongRenShuo
     */
//    @PostMapping("upload")
    public void upload(MultipartFile file) throws IOException {
//        logUtil.getInsertLog(6, 13, "文件上传 - ");
        EasyExcelUtils excelSuperUtil = new EasyExcelUtils();
//        excelSuperUtil.upload(file,service, entity.class);
//        excelSuperUtil.upload(file,实体类对应服务层接口, 实体类.class);
    }






    /**
     * 设置表头
     *
     * @param headMap 表头数组
     * @return {@link List}<{@link List}<{@link String}>>
     */
    private List<List<String>> head(String[] headMap) {
        List<List<String>> list = new ArrayList<List<String>>();

        for (String head : headMap) {
            List<String> headList = new ArrayList<String>();
            headList.add(head);
            list.add(headList);
        }
        return list;
    }


    /**
     * 设置导出的数据内容
     *
     * @param dataList   数据列表
     * @param dataStrMap 数据 str 映射
     * @return {@link List}<{@link List}<{@link Object}>>
     */
    private List<List<Object>> dataList(List<LinkedHashMap<String, Object>> dataList, String[] dataStrMap) {
        List<List<Object>> list = new ArrayList<List<Object>>();
        for (Map<String, Object> map : dataList) {
            List<Object> data = new ArrayList<Object>();
            for (String s : dataStrMap) {
                data.add(map.get(s));
            }
            list.add(data);
        }
        return list;
    }


    /**
     * 检查 类 所有字段是否为 null
     *
     * @param object 对象
     * @return 空属性集合
     */
    public static List<String> checkObjAllFieldsIsNull(Object object) {
        Map<String, Boolean> resultMap = new HashMap<>();
        Field[] fields = object.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            try {
                resultMap.put(field.getName(), field.get(object) == null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        List<String> nullFields = new ArrayList<>();
        for (String field : resultMap.keySet()) {
            if (resultMap.get(field)) {
                nullFields.add(field);
            }
        }
        return nullFields;

    }


}


